package main

import (
	"context"
	"crawler/conf"
	duplicateRpc "crawler/grpc/duplicate-rpc"
	save "crawler/grpc/save-rpc"
	"google.golang.org/grpc"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

var userRe = regexp.MustCompile(conf.USER_COMPILE)
var workerCh = make(chan int, 10)
var saveCh = make(chan save.SendToDbRequest, 20)

// 从redis获取userID，拼接成url，解析出具体的文章，发送给mysql模块存储
func main() {
	// 赋值，启动首次worker
	workerCh <- 1

	for {
		select {
		case <-workerCh:
			go worker()
		case res := <-saveCh:
			// 将res送给mysql存储模块
			if res.Users != nil {
				sendToSave(res)
				// 不要太快，不然可能会有反爬虫机制
				time.Sleep(100 * time.Millisecond)
			}
		}
	}
}

// 获取userId，获取解析结果，并将结果传送到saveCh
func worker() {
	usersData := save.SendToDbRequest{}

	userId := getUserId()
	// 获取不到userId
	if userId == "" {
		// 获取不到则暂停0.5秒，之后再去获取userId
		time.Sleep(500 * time.Millisecond)
		// 调用一次rpc则给worker赋1次值
		workerCh <- 1
		return
	}

	// 获取结果
	usersData = fetchAndParse(userId)
	// 判断结果是否为nil，为nil则0.5秒后再获取userId
	if usersData.Users == nil {
		// 获取不到则暂停0.5秒，之后再去获取userId
		time.Sleep(500 * time.Millisecond)
		// 调用一次rpc则给worker赋1次值
		workerCh <- 1
		return
	} else {
		saveCh <- usersData
		// 调用一次rpc则给worker赋1次值
		workerCh <- 1
	}
}

// 解析用户url并将用户首页的文章信息拿下来
func fetchAndParse(userID string) save.SendToDbRequest {
	res := save.SendToDbRequest{}
	users := []*save.UserData{}

	url := conf.Blog + userID
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal("modular.get-article.fetchAndParse.http.get error=", err)
		return res
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusOK {
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatal(
				"modular.get-article.fetchAndParse.readALL error=", err)
			return res
		}

		match := userRe.FindAllSubmatch(data, -1)

		for _, v := range match {
			arId, err := strconv.Atoi(string(v[2]))
			if err != nil {
				log.Fatal(
					"modular.get-article.fetchAndParse.atoi error=", err)
				continue
			}

			userData := &save.UserData{
				UserId:     userID,
				ArticleId:  int64(arId),
				ArticleUrl: string(v[1]),
			}
			users = append(users, userData)
		}
		res.Users = users
	}
	return res
}

func getUserId() string {
	conn, err := grpc.Dial("172.20.159.204:28080", grpc.WithInsecure())
	if err != nil {
		log.Println("get-article.getUserId.Dial error=", err)
		return ""
	}
	defer conn.Close()

	// 初始化客户端
	cli := duplicateRpc.NewDuplicateClient(conn)

	req := duplicateRpc.GetUserRequest{Get: 0}

	// 调用方法
	res, _ := cli.GetUser(context.Background(), &req)

	return res.User
}

func sendToSave(req save.SendToDbRequest) {
	conn, err := grpc.Dial("172.20.159.208:29090", grpc.WithInsecure())
	if err != nil {
		log.Println("get-article.sendToSave.Dial error=", err)
		// 调用一次rpc则给worker赋1次值
		workerCh <- 1
		return
	}
	defer conn.Close()

	cli := save.NewSendToDbClient(conn)

	res, _ := cli.SendToDb(context.Background(), &req)

	log.Println(res.Message)
}
